import router from '@/router'
import axios from 'axios'
import { Loading } from 'element-ui'
import store from '@/store'
import packageJson from '@/../package.json'

let __callCount = 0 // 累计请求次数
let loadingInstance // 弹窗
let __logoutTime = new Date().getTime() // 登出提示的开始时间点（500ms内只弹一次弹窗）
let __sameDialog = new Date().getTime() // 相同连续错误提示信息（500ms只展示一次）
let __lastErrMsg = '' // 上一次错误提示信息
const DEBOUNCE = 500 // 间隔时间500ms
const t_url = [
  '/purchase/order/getIndexInfo/v001',
  '/purchase/draft/getDraftList/v001',
  '/purchase/staff/getDefaultStaff/v001',
  '/purchase/staff/getStaff/v001',
  '/goods/goods/searchGoodsForInStore/v001',
  '/goods/goods/searchGoodsBatch/v001',
  '/goods/business/searchBusinessForInStore/v001',
  '/commons/user/getInfo/v001'
] // 将null抓换成空字符串的接口地址

const staticURL = ['/purchase/draft/saveDraft/v001', '/goods/region/searchRegion/v001'] // 不想有菊花纹的接口

const noTipsURL = ['/ysb-sync-data/ysbLogin/getUserToken/v001'] // 不需要错误提示的接口

const version = packageJson.version

const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API
})
// service.defaults.baseURL = process.env.BASE_API // 基础url，会在请求url中自动添加前置链接

// request interceptor
service.interceptors.request.use(
  config => {
    // Do something before request is sent
    return setConfig(config)
  },
  error => {
    // Do something with request error
    // console.log(error) // for debug
    Promise.reject(error)
  }
)

service.interceptors.response.use(response => {
  if (!staticURL.includes(response.config.url)) handleEndRequest() // 特定接口不能让全局有菊花纹
  return response
}, error => {
  let isConfig
  if (error.config) isConfig = !staticURL.includes(error.config.url) // 特定接口不能让全局有菊花纹
  if (error.__CANCEL__ || isConfig) {
    handleEndRequest()
  }
  errorMes(error)
  return Promise.reject(error)
})

const SERVERCODE = {
  'success': '40001', // 成功
  'nologin': '40020', // 未登录
  'noPermission': '40006', // 无权限
  'overdue': '40007', // token已经过期
  'payFailed': '40042' // 支付错误时特定信息窗口
}

/**
 *
 * @param options {url:'',params:{},errorCaback}
 * @returns {*}
 */
export function get(options) {
  return request(options, 'get')
}

export function post(options) {
  return request(options, 'post')
}

export function upload(options) {
  return request(options, 'upload')
}

export function request(options, method) {
  for (const key in options.params) {
    // 去除字符串两端空格
    if (typeof options.params[key] === 'string') options.params[key] = options.params[key].trim()
  }

  // if (!options.params.token) options.params.token = token
  // options.params.appVersion = version
  // options.params.platform = 'web'
  // options.params.timestamp = Math.round(new Date().getTime() / 1000).toString()
  return new Promise((resolve, reject) => {
    const axiosOption = {
      method: method || 'post',
      url: options.url,
      timeout: options.timeout || 60000,
      responseType: options.responseType || 'json',
      cancelToken: options.cancelToken
    }
    switch (axiosOption.method) {
      case 'get':
        axiosOption.params = options.params
        break
      case 'post':
        axiosOption.data = options.params
        break
      case 'upload': {
        const formData = new FormData()
        for (const key in options.params) {
          formData.append(key, options.params[key])
        }
        axiosOption.data = formData
        break
      }
    }

    service(axiosOption).then(response => {
      if (response.data) {
        const data = response.data
        if (response.status === 200) {
          if (axiosOption.responseType === 'blob') { // upload请求返回所有
            const _this = this
            const r = new FileReader()
            r.onload = function() {
              try {
                const result = JSON.parse(this.result || r.result)
                switchCase.call(_this, options, result, resolve, reject)
              } catch (err) {
                resolve(response)
              }
            }
            r.readAsText(data)
            return
          }
          if (t_url.includes(axiosOption.url)) {
            dataNullToString(data)
          }
          if (axiosOption.url.includes('http') || axiosOption.url.includes('https')) { // 外部请求链接
            resolve(data)
            return
          }
          if (data.status === 0) { // 处理时空登录成功
            resolve(data)
            return
          }
          switchCase(options, data, resolve, reject)
        } else {
          store.dispatch('message/SetMsgInfo', {
            type: 'error',
            msg: data.message || 'error'
          })
          reject(data)
        }
      }
    }).catch(error => {
      if (!axios.isCancel(error)) {
        reject(error.response || error)
      }
    })
  })
}

export function download(options) {
  for (const key in options.params) {
    // 去除字符串两端空格
    if (typeof options.params[key] === 'string') options.params[key] = options.params[key].trim()
  }
  options.params.appVersion = version
  options.params.platform = 'web'
  options.params.timestamp = Math.round(new Date().getTime() / 1000).toString()
  return new Promise((resolve, reject) => {
    const axiosOption = {
      method: 'post',
      url: options.url,
      timeout: options.timeout || 60000,
      responseType: options.responseType || 'blob',
      cancelToken: options.cancelToken
    }
    axiosOption.data = options.params

    service(axiosOption)
      .then(response => {
        if (response.status === 200) {
          if (axiosOption.responseType === 'blob') {
            const _this = this
            const r = new FileReader()
            r.onload = function() {
              try {
                const result = JSON.parse(this.result || r.result)
                switchCase.call(_this, options, result, resolve, reject)
              } catch (err) {
                resolve(response)
              }
            }
            r.readAsText(response.data)
          } else {
            resolve(response)
          }
        } else {
          store.dispatch('message/', {
            type: 'error',
            msg: '操作失败，请重试！'
          })
          reject(response)
        }
      }).catch(error => {
        if (!axios.isCancel(error)) {
          store.dispatch('message/SetMsgInfo', {
            type: 'error',
            msg: '请求失败，请重试！'
          })
          reject(error)
        }
      })
  })
}

/**
 * 返回数据进行分类处理
 * @param options
 * @param data
 * @param resolve
 * @param reject
 */
function switchCase(options, data, resolve, reject) {
  const __beginTime = new Date().getTime()
  switch (data.code) {
    case SERVERCODE.success: {
      resolve(data)
      break
    }
    case SERVERCODE.nologin: {
      const __happenTime = new Date().getTime();
      (__happenTime - __logoutTime > DEBOUNCE) && !options.url.includes('card/login/loginCheck') && store.dispatch('message/SetMsgInfo', {
        type: 'error',
        msg: data.message || '请重新登录'
      })
      __logoutTime = __happenTime
      store.dispatch('user/logout').then(_ => {
        if (router.currentRoute.name === 'login') return
        router.push('/login')
      })
      break
    }
    case SERVERCODE.noPermission:
    case SERVERCODE.overdue: {
      break
    }
    default:
      !noTipsURL.includes(options.url) && ((__beginTime - __sameDialog > DEBOUNCE) || (__lastErrMsg !== data.message)) && store.dispatch('message/SetMsgInfo', {
        type: 'error',
        msg: data.message || 'error'
      })
      __sameDialog = __beginTime
      __lastErrMsg = data.message
      reject(data)
      break
  }
}

/**
 * 信息报错处理
 * @param error
 */
function errorMes(error) {
  if (error.message === 'Network Error' && error.config.url.endsWith('/license')) {
    store.dispatch('message/SetMsgInfo', {
      type: 'error',
      msg: '无法连接到本地代理程序，请确认代理程序是否运行正常！'
    })
  } else {
    if (error.toString() === 'Error: Request failed with status code 500' || error.toString() === 'Error: Network Error') {
      store.dispatch('message/SetMsgInfo', {
        type: 'error',
        msg: '当前网络连接断开'
      })
    } else if (error.toString() === 'Error: timeout of 60000ms exceeded') {
      store.dispatch('message/SetMsgInfo', {
        type: 'error',
        msg: '网络连接异常，请检查后重试'
      })
    } else {
      store.dispatch('message/SetMsgInfo', {
        type: 'error',
        msg: error.message
      })
    }
  }
}

/**
 * 处理请求头里config
 * @param config
 * @return {*}
 */
function setConfig(config) {
  config.headers['Content-Type'] = 'application/json;charset=UTF-8'
  if (!staticURL.includes(config.url)) handleRequestBefore() // 特定接口不能让全局有菊花纹
  switch (config.method) {
    case 'post':
      // 如果请求头中为application/x-www-form-urlencoded，则需要使用qs.stringify
      config.data = JSON.stringify({
        ...config.data
      })
      break
    case 'upload': {
      config.headers['Content-Type'] = 'multipart/form-data;charset=UTF-8'
      config.method = 'post'
      break
    }
  }
  return config
}

// 将null值转换成空字符串
function dataNullToString(data) {
  for (const i in data) {
    if ((typeof data[i]) === 'object' && data[i] !== null) {
      dataNullToString(data[i])
    } else {
      if (data[i] === null) {
        data[i] = ''
      }
    }
  }
}

// 请求前
function handleRequestBefore() {
  if (__callCount === 0) {
    loadingInstance = Loading.service({
      fullscreen: false,
      lock: false,
      text: '正在拼命加载中',
      spinner: 'el-icon-loading'
    })
  }
  __callCount++
}

// 请求后
function handleEndRequest() {
  __callCount--
  if (__callCount === 0) {
    loadingInstance.close()
  }
}

const ajax = {
  get,
  post,
  upload,
  download
}

export default ajax
